package com.winning.pmph.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import com.winning.pmph.entity.*;
import com.winning.pmph.mapper.LogMapper;
import com.winning.pmph.service.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.util.Asserts;
import org.jetbrains.annotations.NotNull;
import org.jsoup.Jsoup;

import java.util.*;
import java.util.stream.Collectors;

public class KnowledgeEditUtil {

    private static CalculatorService calculatorService = ApplicationContextUtil.getBean(CalculatorService.class);

    private static TagService tagService = ApplicationContextUtil.getBean(TagService.class);

    private static RuleItemService ruleItemService = ApplicationContextUtil.getBean(RuleItemService.class);

    private static ReleasedKnowledgeFieldService releasedKnowledgeFieldService = ApplicationContextUtil.getBean(ReleasedKnowledgeFieldService.class);

    private static KnowledgeService knowledgeService = ApplicationContextUtil.getBean(KnowledgeService.class);

    private static TaskItemService taskItemService = ApplicationContextUtil.getBean(TaskItemService.class);

    private static PlatformService platformService = ApplicationContextUtil.getBean(PlatformService.class);

    /**
     * 统计每个知识字段对应的字数
     *
     * @param tempKnowledgeField
     */
    public static int countWords(TempKnowledgeField tempKnowledgeField) {
        StringBuffer sBuffer = new StringBuffer();
        sBuffer.append(tempKnowledgeField.getDisplayName());
        int kind = tempKnowledgeField.getKind();
        if (0 == kind || 6 == kind) {
            sBuffer.append(StringUtils.isBlank(tempKnowledgeField.getProperty()) ? "" : tempKnowledgeField.getProperty());
        } else if (1 == kind) {
            sBuffer.append(StringUtils.isBlank(tempKnowledgeField.getProperty()) ? "" : tempKnowledgeField.getProperty());
        } else if (2 == kind) {
            //如果是对应的标签，则根据id去查找对应的值
            sBuffer.append(getTagName(tempKnowledgeField.getProperty()));
        } else if (3 == kind || 5 == kind) {
            // 单选或者多选
            sBuffer.append(getRuleName(tempKnowledgeField.getKindValue(), tempKnowledgeField.getProperty()));
        } else {

        }
        String value = sBuffer.toString();
        int len = StringUtils.deleteWhitespace(Jsoup.parse(value).body().text()).length();
        tempKnowledgeField.setWordsCount(len);
        return len;
    }

    private static String getTagName(String tagId) {
        if (StringUtils.isBlank(tagId)) {
            return "";
        }
        List<String> tagName = Lists.newArrayList();
        JSONArray jsonArray = JSONArray.parseArray(tagId);
        for (Object obj : jsonArray) {
            JSONArray innerJsonArray = (JSONArray) obj;
            String id = innerJsonArray.getString(0);
            Tag tag = tagService.getById(id);
            tagName.add(tag.getName());
        }
        return String.join(",", tagName);
    }

    private static String getCalculatorTagName(String tagId) {
        if (StringUtils.isBlank(tagId)) {
            return "";
        }
        List<String> tagName = Lists.newArrayList();

        String tagsId = tagId.substring(1, tagId.lastIndexOf("]"));
        String s = tagsId.replaceAll("\\[", "").replaceAll("\\]", "").replaceAll("\"", "");
        String[] tagIds = s.split(",");
        for (String item : tagIds) {
            if (StringUtils.isNotBlank(item)) {
                Tag tag = tagService.getById(item);
                tagName.add(tag.getName());
            }
        }
        return String.join(",", tagName);
    }

    @SuppressWarnings("unchecked")
    private static String getRuleName(String ruleId, String ruleItemId) {
        if (StringUtils.isBlank(ruleId) || StringUtils.isBlank(ruleItemId)) {
            return "";
        }
        List<RuleItem> ruleItemList = ruleItemService.lambdaQuery()
                .in(RuleItem::getId, Arrays.asList(ruleItemId.split(",")))
                .orderByAsc(RuleItem::getIdx).list();
        return ruleItemList.stream().map(RuleItem::getName).collect(Collectors.joining(","));
    }

    /**
     * 把知识数据从ReleaseKnowledge拷贝到TempKnowledge
     *
     * @param releaseId
     * @return tempKnowledge id
     */
    public static String releaseKnowledge2TempKnowledge(String releaseId) {
        // 取得ReleaseKnowledge
        ReleasedKnowledge releasedKnowledge = ApplicationContextUtil.getBean(ReleasedKnowledgeService.class).getById(releaseId);
        // released_knowledge 转 temp_knowledge;
        TempKnowledge tempKnowledge = JSON.parseObject(JSON.toJSONString(releasedKnowledge), TempKnowledge.class);
        tempKnowledge.setDeleted(0);

        // 取得ReleaseKnowledgeField
        Map<String, Object> extMap = new HashMap<>();
        extMap.put("knowledgeId", releaseId);
        List<ReleasedKnowledgeField> releasedKnowledgeFields = releasedKnowledgeFieldService.lambdaQuery()
                .eq(ReleasedKnowledgeField::getKnowledgeId, releaseId)
                .list();
        ;
        // 转 tempKnowledgeField;
        if (Objects.nonNull(tempKnowledge)) {
            List<TempKnowledgeField> tempKnowledgeFieldList = new ArrayList<>();
            for (ReleasedKnowledgeField releasedKnowledgeField : releasedKnowledgeFields) {
                TempKnowledgeField tempKnowledgeField = JSON.parseObject(JSON.toJSONString(releasedKnowledgeField), TempKnowledgeField.class);
//				BeanUtils.copyProperties(releaseKnowledgeField, tempKnowledgeField);
                tempKnowledgeField.setUpdatedBy(PMPHAppUtil.getCurrentUserEnName());
                tempKnowledgeField.setDisplayName(releasedKnowledgeField.getName());
                tempKnowledgeFieldList.add(tempKnowledgeField);
            }
            // 存储TempKnowledgeFieldList
            TempKnowledge savedTempKnowledge = knowledgeService.addRelease2Temp(tempKnowledge, releaseId,
                    tempKnowledgeFieldList);
            String id = savedTempKnowledge.getId();
            HistoryUtils.save(id, savedTempKnowledge.getName(), History.OPERATE_REEDIT, History.OPERATE_RESULT_SUCCESS);
            FieldCompareUtil.updateLastEditedField(savedTempKnowledge);
            return id;
        }
        return null;
    }

    public static void saveLog(String className, String methodName, String operateType, String sql, String sqlParam) {
        Log log = new Log();
        log.setClassName(className);
        log.setMethodName(methodName);
        log.setOperateType(operateType);
        log.setSql(sql);
        log.setSqlParam(sqlParam);
        ApplicationContextUtil.getBean(LogMapper.class).insert(log);
    }

    public static void resortKnowledgeFields(Knowledge knowledge) {
        // 如果已排序, 则直接返回;
        if (isSorted(knowledge)) {
            return;
        }
        // 先把隐藏字段放到最后, then 按id排序;
        knowledge.setKnowledgeFieldList(knowledge.getKnowledgeFieldList().stream()
                .sorted(Comparator.comparingInt(KnowledgeField::getHidden).thenComparing(KnowledgeField::getId))
                .collect(Collectors.toList()));
        // 先排序显示字段;
        List<KnowledgeField> knowledgeFieldList = knowledge.getKnowledgeFieldList()
                .stream().filter(field -> field.getHidden() == 0).collect(Collectors.toList());
        // 按照固定字段分割;
        List<List<KnowledgeField>> outerList = new ArrayList<>();
        for (KnowledgeField knowledgeField : knowledgeFieldList) {
            if (StringUtils.isNotEmpty(knowledgeField.getKnowledgeLibFieldId())) {
                List<KnowledgeField> innerList = new ArrayList<>();
                innerList.add(knowledgeField);
                outerList.add(innerList);
            } else {
                outerList.get(outerList.size() - 1).add(knowledgeField);
            }
        }
        // 按照内层集合第一个元素的index排序, 扁平化, 为knowledge重新赋值;
        knowledgeFieldList = outerList.stream()
                .sorted(Comparator.comparingInt(item -> item.get(0).getIndex()))
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
        // 把隐藏字段加到最后;
        knowledge.getKnowledgeFieldList().stream().filter(field -> field.getHidden() == 1).forEach(knowledgeFieldList::add);
        knowledge.setKnowledgeFieldList(knowledgeFieldList);
    }

    /**
     * 如果固定字段有序, 则代表该知识字段集合有序
     */
    private static boolean isSorted(Knowledge knowledge) {
        // cntIndex, 代表当前遍历的固定字段index;
        int cntIndex = -1;
        for (KnowledgeField knowledgeField : knowledge.getKnowledgeFieldList()) {
            // 动态字段跳过
            if (StringUtils.isNotEmpty(knowledgeField.getKnowledgeLibFieldId())) {
                if (knowledgeField.getIndex() > cntIndex) {
                    cntIndex = knowledgeField.getIndex();
                } else {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 统计每个公式对应的字数
     *
     * @param id
     */
    public static int calculatorCountWords(String id) {
        StringBuffer sBuffer = new StringBuffer();
        MedicalCalculator medicalCalculator = calculatorService.getMedicalCalculator(id);
        int len = StringUtils.deleteWhitespace(Jsoup.parse(medicalCalculator.getDescribe()).body().text()).length();
        String whereStr = " medical_calc_id='" + id + "'";
        List<MedicalCalculatorField> fields = calculatorService.getMedicalCalculatorField(whereStr);
        for (MedicalCalculatorField field : fields) {
            if (0 == field.getKind() || 6 == field.getKind() || 7 == field.getKind()||4 == field.getKind()) {
                sBuffer.append(field.getProperty());
            }
            if (3 == field.getKind()) {
                sBuffer.append(getCalculatorTagName(field.getProperty()));
            }
            if (1 == field.getKind()) {
                sBuffer.append(StringUtils.join(JSONArray.parseArray(field.getProperty(), String.class), ";"));
            }
        }
        if (medicalCalculator.getFormulaType() == 1) {
            String computationsWhereStr = " medical_calc_id='" + id + "'";
            List<MedicalCalculatorComputation> computations = calculatorService.getMedicalCalculatorComputation(computationsWhereStr);
            sBuffer.append(computations.get(0).getGender());
            sBuffer.append(computations.get(0).getGender());
            String formulatorsWhereStr = " medical_calc_comp_id='" + computations.get(0).getId() + "'";
            List<MedicalCalculatorComputationFormulator> formulators = calculatorService.getMedicalCalculatorComputationFormulator(formulatorsWhereStr);
            for (MedicalCalculatorComputationFormulator formulator : formulators) {
                sBuffer.append(formulator.getFormulator());
            }

            List<MedicalCalculatorComputationItem> computationItems = calculatorService.getMedicalCalculatorComputationItem(formulatorsWhereStr);
            for (MedicalCalculatorComputationItem computationItem : computationItems) {
                sBuffer.append(computationItem.getCode());
                sBuffer.append(computationItem.getName());
                sBuffer.append(computationItem.getUnit());
            }
        } else if (medicalCalculator.getFormulaType() == 2) {
            String scoreTypeWhereStr = " medical_calc_id='" + id + "'";
            List<MedicalCalculatorScoreType> scoreTypes = calculatorService.getMedicalCalculatorScoreType(scoreTypeWhereStr);
            sBuffer.append(scoreTypes.get(0).getExplain());
            String scoresWhereStr = " medical_calc_score_type_id='" + scoreTypes.get(0).getId() + "'";
            List<MedicalCalculatorScore> scores = calculatorService.getMedicalCalculatorScore(scoresWhereStr);
            for (MedicalCalculatorScore score : scores) {
                sBuffer.append(score.getName());
                sBuffer.append(score.getSort());
                String scoreItemsWhereStr = " medical_calc_score_id='" + score.getId() + "'";
                List<MedicalCalculatorScoreItem> scoreItems = calculatorService.getMedicalCalculatorScoreItem(scoreItemsWhereStr);
                for (MedicalCalculatorScoreItem scoreItem : scoreItems) {
                    sBuffer.append(scoreItem.getName());
                    sBuffer.append(scoreItem.getScore());
                }
            }
        }
        int num = StringUtils.deleteWhitespace(Jsoup.parse(sBuffer.toString()).body().text()).length();

        return len + num;
    }

    /**
     * 根据操作和当前的状态来判断操作之后的状态
     *
     * @param knowledgeId 知识ID
     * @param auditLevel  审核级别
     * @param operation   执行的操作
     * @return 操作后的子任务状态
     * @throws Exception 如果无法推断出子任务状态。可能存在为空的参数。
     */
    public static Integer auditStatus(@NotNull String knowledgeId, @NotNull int auditLevel, @NotNull String operation) {
        if ("commit".equals(operation)) {
            return TaskItem.STATUS_COMMIT;
        }

        int status = getTaskItemStatus(knowledgeId);

        if ("save".equals(operation)) {
            return status;
        }

        // ------------ 一级审核中 ------------
        boolean passOnCommit = status == TaskItem.STATUS_COMMIT && "pass".equals(operation);
        boolean rejectOnCommit = status == TaskItem.STATUS_COMMIT && "reject".equals(operation);
        boolean passOnReject2 = status == TaskItem.STATUS_REJECT_2 && "pass".equals(operation);
        boolean rejectOnReject2 = status == TaskItem.STATUS_REJECT_2 && "reject".equals(operation);
        // ------------ 二级审核中 ------------
        boolean passOnPass1 = status == TaskItem.STATUS_PASS_1 && "pass".equals(operation);
        boolean rejectOnPass1 = status == TaskItem.STATUS_PASS_1 && "reject".equals(operation);
        boolean passOnReject3 = status == TaskItem.STATUS_REJECT_3 && "pass".equals(operation);
        boolean rejectOnReject3 = status == TaskItem.STATUS_REJECT_3 && "reject".equals(operation);
        // ------------ 三级审核中 ------------
        boolean passOnPass2 = status == TaskItem.STATUS_PASS_2 && "pass".equals(operation);
        boolean rejectOnPass2 = status == TaskItem.STATUS_PASS_2 && "reject".equals(operation);
        // ------------ 终审通过后驳回 ------------
        boolean passOnFinalReject = status == TaskItem.STATUS_FINAL_REJECT && "pass".equals(operation);
        boolean rejectOnFinalReject = status == TaskItem.STATUS_FINAL_REJECT && "reject".equals(operation);

        if (auditLevel == 1) {
            if (passOnCommit || passOnFinalReject) {
                return TaskItem.STATUS_PASS;
            } else if (rejectOnCommit || rejectOnFinalReject) {
                return TaskItem.STATUS_REJECT;
            }
        } else if (auditLevel == 2) {
            if (passOnCommit || passOnReject2) {
                return TaskItem.STATUS_PASS_1;
            } else if (passOnPass1 || passOnFinalReject) {
                return TaskItem.STATUS_PASS;
            } else if (rejectOnCommit || rejectOnReject2) {
                return TaskItem.STATUS_REJECT;
            } else if (rejectOnPass1 || rejectOnFinalReject) {
                return TaskItem.STATUS_REJECT_2;
            }
        } else {
            if (passOnCommit || passOnReject2) {
                return TaskItem.STATUS_PASS_1;
            } else if (passOnPass1 || passOnReject3) {
                return TaskItem.STATUS_PASS_2;
            } else if (passOnPass2 || passOnFinalReject) {
                return TaskItem.STATUS_PASS;
            } else if (rejectOnCommit || rejectOnReject2) {
                return TaskItem.STATUS_REJECT;
            } else if (rejectOnPass1 || rejectOnReject3) {
                return TaskItem.STATUS_REJECT_2;
            } else if (rejectOnPass2 || rejectOnFinalReject) {
                return TaskItem.STATUS_REJECT_3;
            }
        }
        throw new RuntimeException("无法根据当前操作推断出子任务的状态");
    }

    @SuppressWarnings("unchecked")
    private static int getTaskItemStatus(@NotNull String knowledgeId) {
        String sql = "select ti.*\n" +
                "from task_item as ti\n" +
                "         left join task as t on t.id = ti.task_id\n" +
                "where ti.knowledge_id = '" + knowledgeId + "' and ti.deleted = " + TaskItem.NO_DELETED + "  and " +
                "t.status != " + Task.STATUS_FINISHED + " and ti.status != " + TaskItem.STATUS_RELEASED;
        List<TaskItem> taskItemList = taskItemService.getBaseMapper().executeMultiSelect(sql);
        Asserts.check(taskItemList.size() <= 1, "一条知识与多条已经启动的任务绑定");
        if (taskItemList.size() == 1) {
            return taskItemList.get(0).getStatus();
        } else {
            return TaskItem.STATUS_NOT_COMMIT;
        }
    }

    public static void setFieldValue(KnowledgeField field) {
        // 按照前端格式转换数据;
        int kind = field.getKind();
        String property = field.getProperty();
        if (kind == KnowledgeLibField.FIELD_KIND_STRINGTEXT) {
            field.setFieldValue(property);
        } else if (kind == KnowledgeLibField.FIELD_KIND_RICHEDITOR) {
            field.setFieldValue(property);
        } else if (kind == KnowledgeLibField.FIELD_KIND_REFERENCE) {
            // 前台展示为: 父标签/父标签/子标签;父标签/父标签/子标签 格式;
            List<String> fieldValueList = Lists.newArrayList();
            JSONArray outerArray = JSONArray.parseArray(property);
            if (CollectionUtils.isNotEmpty(outerArray)) {
                // 级联, 后台存储格式为[[1,2,3],[1,2,5]]双重数组, 查询对应的tag;
                Map<String, Tag> tagMap = tagService.selectMap(null);
                for (JSONArray innerArray : outerArray.toJavaList(JSONArray.class)) {
                    if (CollectionUtils.isNotEmpty(innerArray)) {
                        String innerStr = innerArray.stream()
                                .map(tagMap::get)
                                .filter(Objects::nonNull)
                                .map(Tag::getName)
                                .collect(Collectors.joining("/"));
                        fieldValueList.add(innerStr);
                    }
                }
            }
            field.setFieldValue(org.apache.commons.lang3.StringUtils.join(fieldValueList, ";"));
        } else if (kind == KnowledgeLibField.FIELD_KIND_DROPDOWNLIST) {
            if (StringUtils.isNotBlank(property)) {
                RuleItem ruleItem = ruleItemService.getById(property);
                if (Objects.nonNull(ruleItem)) {
                    field.setFieldValue(ruleItem.getName());
                }
            }
        } else if (kind == KnowledgeLibField.FIELD_KIND_IMG) {
            field.setFieldValue(JSON.parseObject(property));
        } else if (kind == KnowledgeLibField.FIELD_KIND_DROPMULTILIST) {
            if (CollectionUtils.isNotEmpty(JSON.parseArray(property))) {
                // property 存储格式为json数组
                List<RuleItem> ruleItemList = ruleItemService.lambdaQuery().in(RuleItem::getId, JSON.parseArray(property, String.class)).orderByAsc(RuleItem::getIdx).list();
                String fieldValue = ruleItemList.stream().map(RuleItem::getName).collect(Collectors.joining(";"));
                // 前台显示格式为分号分割;
                field.setFieldValue(fieldValue);
            }
        } else if (kind == KnowledgeLibField.FIELD_KIND_TEXTAREA) {
            field.setFieldValue(property);
        } else if (kind == KnowledgeLibField.FIELD_KIND_MULTI_VALUE_INPUT) {
            field.setFieldValue(JSON.parseArray(property));
        } else if (kind == KnowledgeLibField.FIELD_KIND_ASSOCIATE_CURRENT_KNOWLEDGE_LIB) {
            field.setFieldValue(JSON.parseArray(property));
        } else if (kind == KnowledgeLibField.FIELD_KIND_ASSOCIATE_OTHER_KNOWLEDGE_LIB) {
            field.setFieldValue(JSON.parseArray(property));
        }
        // 关联应用平台, 数据库存储为json数组, 转为名字字符串拼接;
        else if (kind == KnowledgeLibField.FIELD_KIND_ASSOCIATE_PLATFORM) {
            if (CollectionUtils.isNotEmpty(JSONArray.parseArray(property))) {
                // property 存储格式为json数组
                List<Platform> platforms = platformService.lambdaQuery().in(Platform::getId, JSONArray.parseArray(property)).list();
                String fieldValue = platforms.stream().map(Platform::getName).collect(Collectors.joining(";"));
                // 前台显示格式为分号分割;
                field.setFieldValue(fieldValue);
            }
        } else if (kind == KnowledgeLibField.FIELD_KIND_VIDEO) {
            field.setFieldValue(JSON.parseObject(property));
        } else if (kind == KnowledgeLibField.FIELD_KIND_FILE) {
            field.setFieldValue(JSON.parseArray(property));
        }
        // 其他(后续增加类型), 按照原格式返回;
        else {
            field.setFieldValue(property);
        }
    }
}
